import base64
import pickle

from django_redis import get_redis_connection


class CartHelper:
    def __init__(self, request, response=None, alias='cart'):
        self.request = request
        self.user = request.user
        self.response = response

        if request.user.is_authenticated:
            # 如果用户已登录, 创建redis连接
            self.cart_key = f'cart_{request.user.id}'
            self.cart_selected_key = f'cart_selected_{request.user.id}'
            self.redis_conn = get_redis_connection(alias)

    def _load_cookie_cart(self):
        """加载cookie中的购物车记录数据"""
        cookie_cart = self.request.COOKIES.get('cart_data')

        if cookie_cart:
            cart_dict = pickle.loads(base64.b64decode(cookie_cart))
        else:
            cart_dict = {}

        return cart_dict

    def _set_cookie_cart(self, cart_dict):
        """设置cookie中的购物车记录数据"""
        cookie_cart = base64.b64encode(pickle.dumps(cart_dict))
        self.response.set_cookie('cart_data', cookie_cart, 14 * 3600 * 24)

    def add_cart(self, sku_id, count, selected):
        """购物车记录添加"""
        if self.user.is_authenticated:
            pl = self.redis_conn.pipeline()
            pl.hincrby(self.cart_key, sku_id, count)
            if selected:
                pl.sadd(self.cart_selected_key, sku_id)
            pl.execute()
        else:
            cart_dict = self._load_cookie_cart()
            if sku_id in cart_dict:
                count += cart_dict[sku_id]['count']

            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            self._set_cookie_cart(cart_dict)

    def get_cart(self):
        """购物车记录获取"""
        if self.user.is_authenticated:
            redis_cart = self.redis_conn.hgetall(self.cart_key)
            selected_sku_ids = self.redis_conn.smembers(self.cart_selected_key)

            cart_dict = {}

            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in selected_sku_ids
                }
        else:
            cart_dict = self._load_cookie_cart()
        return cart_dict

    def update_cart(self, sku_id, count, selected):
        if self.user.is_authenticated:
            pl = self.redis_conn.pipeline()
            pl.hset(self.cart_key, sku_id, count)
            if selected:
                pl.sadd(self.cart_selected_key, sku_id)
            else:
                pl.srem(self.cart_selected_key, sku_id)
            pl.execute()
        else:
            cart_dict = self._load_cookie_cart()
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            self._set_cookie_cart(cart_dict)

    def remove_cart(self, sku_id):
        """购物车记录删除"""
        if self.user.is_authenticated:
            pl = self.redis_conn.pipeline()
            pl.hdel(self.cart_key, sku_id)
            pl.srem(self.cart_selected_key, sku_id)
            pl.execute()
        else:
            cart_dict = self._load_cookie_cart()
            cart_dict.pop(sku_id)
            self._set_cookie_cart(cart_dict)

    def select_cart(self, selected):
        """购物车记录全选和取消全选"""
        if self.user.is_authenticated:
            sku_ids = self.redis_conn.hkeys(self.cart_key)
            cart_selected_key = f'cart_selected_{self.user.id}'

            if selected:
                self.redis_conn.sadd(cart_selected_key, *sku_ids)
            else:
                self.redis_conn.srem(cart_selected_key, *sku_ids)
        else:
            cart_dict = self._load_cookie_cart()
            if cart_dict:
                for sku_id in cart_dict:
                    cart_dict[sku_id]['selected'] = selected
                self._set_cookie_cart(cart_dict)

    def get_redis_selected_cart(self):
        """获取redis中被勾选的记录"""
        redis_conn = self.redis_conn
        redis_cart = redis_conn.hgetall(self.cart_key)
        redis_selected = redis_conn.smembers(self.cart_selected_key)

        cart_dict = {}
        for sku_id, count in redis_cart.items():
            if sku_id in redis_selected:
                cart_dict[int(sku_id)] = int(count)
        return cart_dict

    def clear_redis_selected_cart(self):
        """清除勾选"""
        redis_conn = self.redis_conn
        redis_selected = redis_conn.smembers(self.cart_selected_key)

        redis_conn.hdel(self.cart_key, *redis_selected)
        redis_conn.srem(self.cart_selected_key, *redis_selected)

    def merge_cookie_cart_to_redis(self):
        """将cookie中的购物车数据合并到redis"""
        # 加载 cookie 中的购物车记录数据
        cart_dict = self._load_cookie_cart()

        if not cart_dict:
            return None

        # 保存 cookie 购物车记录数据中对应商品的id及添加的数量count
        carts = {}
        # 保存 cookie 购物车记录数据中被勾选的记录对应商品的id
        redis_cart_selected_add = []
        # 保存 cookie 购物车记录数据中未被勾选的记录对应商品的id
        redis_cart_selected_remove = []

        # 遍历 cookie 中的购物车记录数据，分别存放的不同的位置
        for sku_id, values, in cart_dict.items():
            count = values['count']
            selected = values['selected']
            # 保存购物车记录对应商品id和数量count
            carts[sku_id] = count

            if selected:
                redis_cart_selected_add.append(sku_id)
            else:
                redis_cart_selected_remove.append(sku_id)

            self.redis_conn.hmset(self.cart_key, carts)

            if redis_cart_selected_add:
                self.redis_conn.sadd(self.cart_selected_key, *redis_cart_selected_add)

            if redis_cart_selected_remove:
                self.redis_conn.srem(self.cart_selected_key, *redis_cart_selected_remove)

            self.response.delete_cookie('cart_data')